import { Select as ASelect } from 'antd';
import type { SelectProps as ASelectProps, OptionProps } from 'antd/lib/select';
import React, { useState, useEffect } from 'react';
import type { PluginCtx } from 'sula/es/types/ctx';
import type { FocusEvent, ChangeEvent } from 'react';
import isFunction from 'lodash/isFunction';
import isString from 'lodash/isString';

export type SelectSourceItem = {
  text: any;
} & Omit<OptionProps, 'children'>;

export interface SelectGroupItem {
  text: any;
  children: SelectSourceItem[];
}
type Formatter = string | ((value: string | number) => any);

export interface SelectProps extends Omit<ASelectProps<any>, 'onChange' | 'onBlur'> {
  source: SelectSourceItem[] | SelectGroupItem[];
  formatter?: Formatter;
  triggerEvent?: string;
  inputFormatter?: Formatter;
  outputFormatter?: Formatter;
  splitChart?: string;
  onChange?: (nativeEvent: ChangeEvent<HTMLInputElement>, value: string, ctx?: PluginCtx) => void;
  onBlur?: (nativeEvent: FocusEvent<HTMLInputElement>, value: string, ctx?: PluginCtx) => void;
  ctx?: PluginCtx;
}

const FormatterSelect: React.FC<SelectProps> = ({
  source = [],
  value,
  formatter = 'splitToNumber',
  onChange,
  onBlur,
  splitChart = ',',
  inputFormatter,
  outputFormatter,
  ...restProps
}) => {
  const [formatterValue, setFormatterValue] = useState(value);
  const { ctx = undefined, mode = undefined } = restProps;

  const isMutipleMode = () => {
    return mode === 'multiple' || mode === 'tags';
  };

  const resetSelectValue = () => {
    if (isMutipleMode()) {
      setFormatterValue([]);
    } else {
      setFormatterValue(null);
    }
  };
  // 方法扩展统一入口进行值初始化
  const setInitValue = (val: any) => {
    let inputValue = val;
    if (!val) {
      resetSelectValue();
      return;
    }
    if (isFunction(inputFormatter)) {
      // 自定义格式化函数优先级最高
      inputValue = inputFormatter(val);
    } else if (!isMutipleMode()) {
      // 若不是多选模式，不进行下一步格式化
      inputValue = val;
    } else if (formatter === 'splitToNumber' && isString(inputValue)) {
      inputValue =
        (inputValue &&
          inputValue.split(splitChart).map((option) => {
            return Number(option);
          })) ||
        [];
    } else if (formatter === 'splitToString' && isString(inputValue)) {
      inputValue = (inputValue && inputValue.split(splitChart)) || [];
    }
    setFormatterValue(inputValue);
  };

  // 方法扩展统一出口进行值不同规则的format
  const setOutputValue = (val: any) => {
    let outputValue = val;
    if (isFunction(outputFormatter)) {
      outputValue = outputFormatter(val);
    } else if (!isMutipleMode()) {
      outputValue = val;
    } else if (formatter === 'splitToNumber' || formatter === 'splitToString') {
      outputValue = val.join(splitChart);
    }
    return outputValue;
  };
  useEffect(() => {
    setInitValue(value);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [value]);

  const renderOption = (item: SelectSourceItem) => {
    const { text, itemValue, ...itemRestProps } = item;
    return (
      <ASelect.Option value={itemValue} key={text + itemValue} {...itemRestProps}>
        {text}
      </ASelect.Option>
    );
  };
  const renderGroupOptions = (group: SelectGroupItem) => {
    return (
      <ASelect.OptGroup key={group.text} label={group.text}>
        {(group.children as SelectSourceItem[]).map((item) => {
          return renderOption(item);
        })}
      </ASelect.OptGroup>
    );
  };
  const handleInputChange = (changeValue: any, option: any) => {
    const originValue = changeValue;
    const outputValue = setOutputValue(originValue);
    onChange?.(outputValue, option, ctx);
  };

  return (
    <ASelect
      {...restProps}
      value={formatterValue as any}
      onChange={(changeValue, option) => {
        handleInputChange(changeValue, option);
      }}
    >
      {source.map((item) => {
        if ((item as SelectGroupItem).children) {
          return renderGroupOptions(item as SelectGroupItem);
        }
        return renderOption(item as SelectSourceItem);
      })}
    </ASelect>
  );
};
export default FormatterSelect;
